case 4: *val = *(u32 *)addr; break;
case 8: *val = *(unsigned long *)addr; break;
}
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int write(
case 4: *(u32 *)addr = (u32)val; break;
case 8: *(unsigned long *)addr = val; break;
}
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int cmpxchg(
case 4: *(u32 *)addr = (u32)new; break;
case 8: *(unsigned long *)addr = new; break;
}
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int cmpxchg8b(
unsigned long addr = offset;
((unsigned long *)addr)[0] = new_lo;
((unsigned long *)addr)[1] = new_hi;
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static struct x86_emulate_ops emulops = {
regs.eax = (unsigned long)res;
*res = 0x7FFFFFFF;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x92345677) ||
(regs.eflags != 0xa94) ||
(regs.eip != (unsigned long)&instr[2]) )
regs.ecx = 0x12345678;
regs.eax = 0x7FFFFFFF;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(regs.ecx != 0x12345678) ||
(regs.eax != 0x92345677) ||
(regs.eflags != 0xa94) ||
#endif
regs.eax = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x92345677) ||
(regs.ecx != 0x8000000FUL) ||
(regs.eip != (unsigned long)&instr[2]) )
regs.ecx = ~0UL;
regs.eax = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x92345677) ||
(regs.ecx != 0x92345677UL) ||
(regs.eip != (unsigned long)&instr[2]) )
regs.ecx = 0xAA;
regs.ebx = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x923456AA) ||
(regs.eflags != 0x244) ||
(regs.eax != 0x92345677UL) ||
regs.ecx = 0xFF;
regs.ebx = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x923456AA) ||
((regs.eflags&0x240) != 0x200) ||
(regs.eax != 0xAABBCCAA) ||
regs.ecx = 0x12345678;
regs.eax = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x12345678) ||
(regs.eflags != 0x200) ||
(regs.ecx != 0x923456AA) ||
regs.ecx = 0xDDEEFF00L;
regs.ebx = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0xDDEEFF00) ||
(regs.eflags != 0x244) ||
(regs.eax != 0x923456AAUL) ||
regs.esi = (unsigned long)res + 0;
regs.edi = (unsigned long)res + 2;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x44554455) ||
(regs.eflags != 0x200) ||
(regs.ecx != 22) ||
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x2233445D) ||
((regs.eflags&0x201) != 0x201) ||
(regs.eip != (unsigned long)&instr[4]) )
regs.eax = -32;
regs.edi = (unsigned long)(res+1);
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x2233445E) ||
((regs.eflags&0x201) != 0x201) ||
(regs.eip != (unsigned long)&instr[3]) )
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(res[0] != 0x9999AAAA) ||
(res[1] != 0xCCCCFFFF) ||
((regs.eflags&0x240) != 0x240) ||
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(res[0] != 0x9999AAAA) ||
(res[1] != 0xCCCCFFFF) ||
(regs.eax != 0x9999AAAA) ||
regs.eax = (unsigned long)res;
*res = 0x82;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x82) ||
(regs.ecx != 0xFFFFFF82) ||
((regs.eflags&0x240) != 0x200) ||
regs.eax = (unsigned long)res;
*res = 0x1234aa82;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x1234aa82) ||
(regs.ecx != 0xaa82) ||
((regs.eflags&0x240) != 0x200) ||
regs.eax = 0x12345678;
*res = 0x11111111;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x11116789) ||
(regs.eax != 0x12341111) ||
((regs.eflags&0x240) != 0x200) ||
regs.eip = (unsigned long)&instr[0];
regs.eax = 0x00000000;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(regs.eax != 0x0000ffff) ||
((regs.eflags&0x240) != 0x200) ||
(regs.eip != (unsigned long)&instr[2]) )
regs.eax = 0x12345678;
regs.ebp = 0xaaaaaaaa;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(regs.eax != 0xaaaaaab2) ||
((regs.eflags&0x240) != 0x200) ||
(regs.eip != (unsigned long)&instr[3]) )
bcdres_emul |= (regs.eflags & EFLG_SF) ? 0x400 : 0;
bcdres_emul |= (regs.eflags & EFLG_CF) ? 0x200 : 0;
bcdres_emul |= (regs.eflags & EFLG_AF) ? 0x100 : 0;
- if ( (rc != 0) || (regs.eax > 255) ||
+ if ( (rc != X86EMUL_OKAY) || (regs.eax > 255) ||
(regs.eip != (unsigned long)&instr[1]) )
goto fail;
if ( (i++ & 8191) == 0 )
printf(".");
rc = x86_emulate(&ctxt, &emulops);
- if ( rc != 0 )
+ if ( rc != X86EMUL_OKAY )
{
printf("failed at %%eip == %08x\n", (unsigned int)regs.eip);
return 1;
if ( (rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0 )
{
propagate_page_fault(addr + bytes - rc, 0); /* read fault */
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
}
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int ptwr_emulated_update(
if ( (rc = copy_from_user(&full, (void *)addr, sizeof(paddr_t))) != 0 )
{
propagate_page_fault(addr+sizeof(paddr_t)-rc, 0); /* read fault */
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
}
/* Mask out bits provided by caller. */
full &= ~((((paddr_t)1 << (bytes*8)) - 1) << (offset*8));
/* Finally, drop the old PTE. */
put_page_from_l1e(gl1e_to_ml1e(d, ol1e), d);
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int ptwr_emulated_write(
struct page_info *page;
l1_pgentry_t pte;
struct ptwr_emulate_ctxt ptwr_ctxt;
+ int rc;
LOCK_BIGLOCK(d);
IS_COMPAT(d) ? 32 : BITS_PER_LONG;
ptwr_ctxt.cr2 = addr;
ptwr_ctxt.pte = pte;
- if ( x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops) )
+
+ rc = x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops);
+ if ( rc == X86EMUL_UNHANDLEABLE )
goto bail;
UNLOCK_BIGLOCK(d);
gpf:
/* Inject #GP(0). */
hvm_inject_exception(TRAP_gp_fault, 0, 0);
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
}
static int
// In this case, that is only a user vs supervisor access check.
//
if ( (rc = hvm_copy_from_guest_virt(val, addr, bytes)) == 0 )
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
/* If we got here, there was nothing mapped here, or a bad GFN
* was mapped here. This should never happen: we're here because
if ( access_type == hvm_access_insn_fetch )
errcode |= PFEC_insn_fetch;
hvm_inject_exception(TRAP_page_fault, errcode, addr + bytes - rc);
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
}
static int
/* Hit the cache. Simple memcpy. */
*val = 0;
memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes);
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int
if ( (rc = copy_from_user((void *)val, (void *)offset, bytes)) != 0 )
{
propagate_page_fault(offset + bytes - rc, 0); /* read fault */
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
}
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int
* page is no longer a page table. This behaviour differs from native, but
* it seems very unlikely that any OS grants user access to page tables.
*/
- if ( (regs->error_code & PFEC_user_mode) ||
- x86_emulate(&emul_ctxt.ctxt, emul_ops) )
+ r = X86EMUL_UNHANDLEABLE;
+ if ( !(regs->error_code & PFEC_user_mode) )
+ r = x86_emulate(&emul_ctxt.ctxt, emul_ops);
+
+ if ( (r == X86EMUL_UNHANDLEABLE) || (r == X86EMUL_EXCEPTION) )
{
SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n",
mfn_x(gmfn));
ASSERT(((vaddr & ~PAGE_MASK) + bytes) <= PAGE_SIZE);
if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
skip = safe_not_to_verify_write(mfn, addr, src, bytes);
memcpy(addr, src, bytes);
sh_unmap_domain_page(addr);
shadow_audit_tables(v);
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
int
mfn_t mfn;
void *addr;
unsigned long prev;
- int rv = X86EMUL_CONTINUE, skip;
+ int rv = X86EMUL_OKAY, skip;
ASSERT(shadow_locked_by_me(v->domain));
ASSERT(bytes <= sizeof(unsigned long));
return X86EMUL_UNHANDLEABLE;
if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
skip = safe_not_to_verify_write(mfn, &new, &old, bytes);
mfn_t mfn;
void *addr;
u64 old, new, prev;
- int rv = X86EMUL_CONTINUE, skip;
+ int rv = X86EMUL_OKAY, skip;
ASSERT(shadow_locked_by_me(v->domain));
return X86EMUL_UNHANDLEABLE;
if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
old = (((u64) old_hi) << 32) | (u64) old_lo;
new = (((u64) new_hi) << 32) | (u64) new_lo;
#define mode_64bit() (def_ad_bytes == 8)
-#define fail_if(p) \
-do { \
- rc = (p) ? X86EMUL_UNHANDLEABLE : 0; \
- if ( rc ) goto done; \
+#define fail_if(p) \
+do { \
+ rc = (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; \
+ if ( rc ) goto done; \
} while (0)
/* In future we will be able to generate arbitrary exceptions. */
uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes;
unsigned int lock_prefix = 0, rep_prefix = 0;
- int rc = 0;
+ int rc = X86EMUL_OKAY;
struct operand src, dst;
/* Data operand effective address (usually computed from ModRM). */
{
op_bytes = def_op_bytes = 4;
#ifndef __x86_64__
- return -1;
+ return X86EMUL_UNHANDLEABLE;
#endif
}
*ctxt->regs = _regs;
done:
- return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+ return rc;
special_insn:
dst.type = OP_NONE;
}
printk("\n");
#endif
- return -1;
+ return X86EMUL_UNHANDLEABLE;
}
x86_seg_idtr
};
+/*
+ * Return codes from state-accessor functions and from x86_emulate().
+ */
+ /* Completed successfully. State modified appropriately. */
+#define X86EMUL_OKAY 0
+ /* Unhandleable access or emulation. No state modified. */
+#define X86EMUL_UNHANDLEABLE 1
+ /* Exception raised and requires delivery. */
+#define X86EMUL_EXCEPTION 2
+ /* Retry the emulation for some reason. No state modified. */
+#define X86EMUL_RETRY 3
+ /* (cmpxchg accessor): CMPXCHG failed. Maps to X86EMUL_RETRY in caller. */
+#define X86EMUL_CMPXCHG_FAILED 3
+
/*
* These operations represent the instruction emulator's interface to memory.
*
* 1. If the access fails (cannot emulate, or a standard access faults) then
* it is up to the memop to propagate the fault to the guest VM via
* some out-of-band mechanism, unknown to the emulator. The memop signals
- * failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will
+ * failure by returning X86EMUL_EXCEPTION to the emulator, which will
* then immediately bail.
* 2. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
* cmpxchg8b_emulated need support 8-byte accesses.
* 3. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
*/
-/* Access completed successfully: continue emulation as normal. */
-#define X86EMUL_CONTINUE 0
-/* Access is unhandleable: bail from emulation and return error to caller. */
-#define X86EMUL_UNHANDLEABLE 1
-/* Terminate emulation but return success to the caller. */
-#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
-#define X86EMUL_RETRY_INSTR 2 /* retry the instruction for some reason */
-#define X86EMUL_CMPXCHG_FAILED 2 /* cmpxchg did not see expected value */
struct x86_emulate_ops
{
/*